package per.cyl.iotest.socket;


import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * @author 陈玉林
 * @desc TODO
 * @date 2020/7/16 11:11
 */
public class NioSocketServer {
    public static void main(String[] args) {
        try {
            //创建channel
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            //channel注册为非阻塞
            serverSocketChannel.configureBlocking(false);
            //channel绑定端口
            serverSocketChannel.bind(new InetSocketAddress(8080));

            //创建选择器
            Selector selector = Selector.open();
            //channel绑定选择器并注册感兴趣的事件
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

            while (true) {
                //等待三秒，看是否有事件进入
                if (selector.select(3000) != 0) {
                    //获取SelectionKey集合 selectionKeys保存了请求selector和channel信息
                    Set<SelectionKey> selectionKeys = selector.selectedKeys();
                    System.out.println("服务器收到请求，SelectionKey的长度为：" + selectionKeys.size());
                    Iterator<SelectionKey> selectionKeyIterator = selectionKeys.iterator();
                    while (selectionKeyIterator.hasNext()) {
                        SelectionKey selectionKey = selectionKeyIterator.next();
                        //获取到请求后移除请求
                        selectionKeyIterator.remove();
                        if (selectionKey.isAcceptable()) {
                            accept(selectionKey);
                        } else if (selectionKey.isReadable()) {
                            read(selectionKey);
                        } else if (selectionKey.isWritable()) {
                            write(selectionKey);
                        }

                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private static void write(SelectionKey selectionKey) {
        System.out.println("------------------写事件------------------");
        ByteBuffer buf = (ByteBuffer) selectionKey.attachment();
        buf.put("客户端返回".getBytes());
        buf.flip();
        SocketChannel sc = (SocketChannel) selectionKey.channel();
        while (buf.hasRemaining()) {
            try {
                sc.write(buf);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        buf.compact();
    }

    private static void read(SelectionKey key) throws IOException {
        System.out.println("------------------读事件------------------");
        SocketChannel socketChannel = (SocketChannel) key.channel();
        try {
            ByteBuffer readBuffer = ByteBuffer.allocate(1024);

            ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
            int bytesRead = socketChannel.read(readBuffer);
            if (bytesRead > 0) {
                readBuffer.flip();
                byte[] bytes = new byte[bytesRead];
                readBuffer.get(bytes, 0, bytesRead);
                String str = new String(bytes);
                System.out.println(str);
                readBuffer.clear();

                writeBuffer.put("服务端返回数据：".getBytes());
                writeBuffer.put(bytes);
                writeBuffer.flip();
                while (writeBuffer.hasRemaining()) {
                    socketChannel.write(writeBuffer);
                }
                writeBuffer.compact();

            } else {
                System.out.println("关闭的连接");
                key.cancel();
                socketChannel.close();
            }

        } catch (Exception e) {
            e.printStackTrace();
            key.cancel();
            socketChannel.close();
        }
    }

    private static void accept(SelectionKey key) throws IOException {
        System.out.println("------------------连接事件------------------");
        ServerSocketChannel ssChannel = (ServerSocketChannel) key.channel();
        SocketChannel sc = ssChannel.accept();
        sc.configureBlocking(false);
        sc.register(key.selector(), SelectionKey.OP_READ);
    }
}
